<?php

namespace common\components\fast_api;

use Yii;
use yii\base\DynamicModel;
use yii\base\Exception;
use yii\base\InlineAction;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\db\ActiveQueryInterface;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
use yii\web\BadRequestHttpException;

class Controller extends \yii\rest\Controller
{
    /**
     * 参数的检验规则
     * 次方法返回的预设规则将在beforeAction事件中被校验
     * - 简单示例：
     * ```php
     * return [
     *    //设置 indexAction()的rule
     *    'index' => [
     *         ['param1','string','min'=>1,'max'=>6],
     *         ['param2','integer'],
     *    ];
     * ];
     * ```
     * - 可以用 * 号通配所有的actions
     * ```php
     * return [
     *    '*' => [
     *         ['user_id','integer']//所有的user_id都将被IntegerVa校验
     *    ];
     * ];
     * ```
     * - 可以 指定到某个 model 的 rules
     * ```php
     * return [
     *    //设置并唯一用 YouModel::rules() 检验路由 index
     *    'index' => 'app\modes\YouModel';
     * ];
     * ```
     * - 更多检验器的设置方法见
     * http://www.yiichina.com/doc/guide/2.0/input-
     *
     * @return array
     */
    public function rules()
    {
        return [];
    }

    /**
     * action参数注入
     * @param \yii\base\Action $action
     * @param array $params
     * @return array
     * @throws ApiException
     * @throws BadRequestHttpException
     * @throws Exception
     * @throws \ReflectionException
     * @throws \yii\base\InvalidConfigException
     */
    public function bindActionParams($action, $params)
    {
        if ($action instanceof InlineAction) {
            $method = new \ReflectionMethod($this, $action->actionMethod);
        } else {
            $method = new \ReflectionMethod($action, 'run');
        }
        $params = array_merge($params, $this->request->getBodyParams());
        $rule = $this->getRule($action);
        if ($rule) {
            if($rule instanceof Model){
                $model = $rule;
                $model->load($params,'');
            }else{
                $model = DynamicModel::validateData($params, $rule);
            }
            $model->validate();
            if ($model->hasErrors()) {
                throw new ApiException(422, $model);
            }
            $params = array_replace($params, $model->getAttributes());
        }
        $args = [];
        $missing = [];
        foreach ($method->getParameters() as $param) {
            $name = $param->getName();
            if (array_key_exists($name, $params)) {
                if ($param->getType() && $param->getType()->getName() === 'array') {
                    $args[] = (array)$params[$name];
                } elseif (!is_array($params[$name])) {
                    $args[] = $params[$name];
                } else {
                    throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [
                        'param' => $name,
                    ]));
                }
            } elseif ($param->isDefaultValueAvailable()) {
                $args[] = $params[$name] = $param->getDefaultValue();
            } else {
                $missing[] = $name;
            }
        }
        if (!empty($missing)) {
            throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [
                'params' => implode(', ', $missing),
            ]));
        }
        $this->actionParams = $params;
        return $args;
    }

    /**
     * 获取action对应的rule规则
     * @param \yii\base\Action $action $action
     * @return array|\yii\base\Model
     * @throws \Exception
     */
    protected function getRule($action)
    {
        $rules = $this->rules();
        $commonRule = isset($rules['*']) ? $rules['*'] : [];
        $uniqueRule = isset($rules[$action->id]) ? $rules[$action->id] : [];
        if (is_string($uniqueRule) || (is_array($uniqueRule) && isset($uniqueRule['class']))) {
            /* @var $model \yii\base\Model */
            $model = Yii::createObject($uniqueRule);
            //$uniqueRule = $model->rules();
            return $model;
        }
        return array_merge($commonRule, $uniqueRule);
    }

    public function apiSuccess($data = [], $message = "ok")
    {
        return [
            'code' => 200,
            'message' => $message,
            'data' => $data,
        ];
    }

    public function apiError($message = "error", $data = [], $code = 560)
    {
        return [
            'code' => $code,
            'message' => $message,
            'data' => $data,
        ];
    }

    /**
     * @param ActiveQueryInterface $query
     * @param $page
     * @param $pageSize
     * @param $sort
     * @return ApiPageData
     */
    public function apiPageData(ActiveQueryInterface $query, $page = 1, $pageSize = 10, $sort = null)
    {
        $pageData = new ApiPageData();
        if (!$sort) $sort = ['defaultOrder' => [
            'id' => SORT_DESC,
        ]];
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'page' => $page - 1,
                'pageSize' => $pageSize,
            ],
            'sort' => $sort,
        ]);
        $dataProvider->prepare();
        $pageData->dataProvider = $dataProvider;
        $pageData->meta = [
            'totalCount' => $dataProvider->totalCount,
            'pageCount' => $dataProvider->pagination->pageCount,
            'currentPage' => $dataProvider->pagination->page + 1,
            'perPage' => $dataProvider->pagination->pageSize,
        ];
        return $pageData;
    }
}
